
package com.smartfit;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;

import android.os.Environment;
import android.util.Xml;

public class ExamplarDB
{
	// DB파일 저장위치
	private final String m_strDataPath = Environment.getExternalStorageDirectory() + "/android/data/com.smartfit";
	// Config 파일 이름
	final private String CONFIG_FILE_NAME_TAG = "PatternDB.xml"; 
	// Config 파일 태그
	final private String CONFIG_MAIN_TAG = "PatternDB"; 
	// 패턴 갯수 태그
	final private String CONFIG_MAIN_NUM_PATTERN_TAG = "NumPatterns";
	// 대표 최대 갯수
	final private String CONFIG_MAIN_MAX_EXAMPLARS_TAG = "MaxExamplars";
	// 각도 한계값
	final private String CONFIG_MAIN_ANGLE_THRESHOLD_TAG = "AngleThreshold";
	// 거리 한계값
	final private String CONFIG_MAIN_DISTANCE_THRESHOLD_TAG = "DistanceThreshold";
	// 패턴  태그
	final private String CONFIG_PATTERN_TAG = "Pattern";
	// 패턴 아이디  태그
	final private String CONFIG_PATTERN_ID_TAG = "id";
	// 패턴 설명 태그
	final private String CONFIG_PATTERN_DESCRIPTION_TAG = "description";
	// 패턴 아이콘 태그
	final private String CONFIG_PATTERN_ICON_TAG = "icon";

	// 데이터에 중력값을 포함할 지 유무
	private boolean m_bIsContainedGravity = true;
	// 칼만필터 적용 휴무
	private boolean m_bIsAppliedKalmanFilter = true;
	// 가속도 ^ 2
	private boolean m_bIsAppliedSquare = true;
	// 프레임 맞춤
	private boolean m_bIsKeepFrame = true;
	// 노이즈
	private double m_fNoise = 0.0; 
	// 성공 한계값
	private int m_iAngleThreshold = 50;
	// 거리 한계값
	int m_iDistanceThreshold = 10;
	// 패턴수
//	private int m_iNumPatterns = 0;
	// 
	
	// 시작체크
	private boolean m_bIsEnableCheckStart = true;
	private double m_fCheckStartConstant1 = 0.0f;
	private double m_fCheckStartConstant2 = 0.0f;
	private double m_fCheckStartThreshold = 0.0f;
	
	// 그래프 패턴
	private int m_iNumCompareFrameForPattern = 5;
	private double m_fCompareThresholdForPattern = 0.5;
	
	// 대표 최대 갯수
	private int m_iNumMaxExamplars = 3;
	// 샘플데이터 시간간격
	private int m_iTimeInterval = 100;
	// DB
	HashMap<Integer , Examplar> m_Examplars;
	
	//
	//
	//

	public String GetDataPath()
	{
		return m_strDataPath;
	}
	
	public void SetGravityContain( boolean bIsContainedGravity )
	{
		m_bIsContainedGravity = bIsContainedGravity;
	}
	
	public boolean IsContainedGravity()
	{
		return m_bIsContainedGravity;
	}
	
	public void SetKalmanFilterApply( boolean bIsAppliedKalmanFilter )
	{
		m_bIsAppliedKalmanFilter = bIsAppliedKalmanFilter;
	}
	
	public boolean IsAppliedKalmanFilter()
	{
		return m_bIsAppliedKalmanFilter;
	}
	
	public void SetSquareApply( boolean bIsAppliedSquare )
	{
		m_bIsAppliedSquare = bIsAppliedSquare;
	}
	
	public boolean IsAppliedSquare()
	{
		return m_bIsAppliedSquare;
	}
	
	public void SetFrameKeep( boolean bIsKeepFrame )
	{
		m_bIsKeepFrame = bIsKeepFrame;
	}
	
	public boolean IsKeepFrame()
	{
		return m_bIsKeepFrame;
	}
	
	public void SetNoiseValue( double fNoise )
	{
		m_fNoise = fNoise;
	}
	
	public double GetNoiseValue()
	{
		return m_fNoise;
	}
	
	public void SetAngleThreshold( int iThreshold )
	{
		m_iAngleThreshold = iThreshold;
	}
	
	public int GetAngleThreshold()
	{
		return m_iAngleThreshold;
	}
	
	public void SetDistanceThreshold( int iThreshold )
	{
		m_iDistanceThreshold = iThreshold;
	}
	
	public int GetDistanceThreshold()
	{
		return m_iDistanceThreshold;
	}

	public int GetNumPatters()
	{
		return 0;//m_iNumPatterns;
	}
	
	public void SetEnableCheckStart( boolean bIsEnable )
	{
		m_bIsEnableCheckStart = bIsEnable;
	}
	
	public boolean IsEnabledCheckStart()
	{
		return m_bIsEnableCheckStart;
	}

	public void SetCheckStartConstant1( double fConstant )
	{
		m_fCheckStartConstant1 = fConstant;
	}

	public double GetCheckStartConstant1()
	{
		return m_fCheckStartConstant1;
	}

	public void SetCheckStartConstant2( double fConstant )
	{
		m_fCheckStartConstant2 = fConstant;
	}

	public double GetCheckStartConstant2()
	{
		return m_fCheckStartConstant2;
	}

	public void SetCheckStartThreshold( double fThreshold )
	{
		m_fCheckStartThreshold = fThreshold;
	}

	public double GetCheckStartThreshold()
	{
		return m_fCheckStartThreshold;
	}

	// 그래프 패턴

	public void SetCompareFrameForPattern( int iFrame )
	{
		m_iNumCompareFrameForPattern = iFrame;
	}
	
	public int GetCompareFrameForPattern()
	{
		return m_iNumCompareFrameForPattern;
	}
	
	public void SetCompareThresholdForPattern( double fThreshold )
	{
		m_fCompareThresholdForPattern = fThreshold;
	}
	
	public double GetCompareThresholdForPattern()
	{
		return m_fCompareThresholdForPattern;
	}

	public void SetNumMaxExamplars( int iNumMaxExamplars )
	{
		m_iNumMaxExamplars = iNumMaxExamplars;
	}
	
	public int GetNumMaxExamplars()
	{
		return m_iNumMaxExamplars;
	}
	
	// 샘플데이터 시간간격 설정
	public void SetTimeInterval( int iInterval )
	{
		m_iTimeInterval = iInterval;
	}
	
	// 샘플데이터 시간간격 얻기
	public int GetTimeInterval()
	{
		return m_iTimeInterval;
	}
	
	// 샘플데이터 시간간격 얻기
	
	public boolean Initialize()
	{
		// 대표값 저장공간 생성
		m_Examplars = new HashMap<Integer , Examplar>();
		
		// 대표값 정보 로딩
		if ( LoadConfigFile() == false )
		{
			// 없으면 생성
			return WriteConfigFile();
		}
		
		return true;
	}
	
	public boolean WriteConfigFile()
	{
		try
		{
			File file = new File( m_strDataPath );
			if ( !file.exists() )
			{
				file.mkdirs();
			}
			
			file = new File( m_strDataPath + "/" + CONFIG_FILE_NAME_TAG );
			
			if ( !file.exists() )
			{
				file.createNewFile();
			}
			
			FileOutputStream fos = new FileOutputStream( file );
			XmlSerializer serializer = Xml.newSerializer();
			
            //we set the FileOutputStream as output for the serializer, using UTF-8 encoding
            serializer.setOutput( fos , "UTF-8" );
            
            //Write <?xml declaration with encoding (if encoding not null) and standalone flag (if standalone not null)
            serializer.startDocument( null , Boolean.valueOf( true ) );
            //set indentation option
            serializer.setFeature( "http://xmlpull.org/v1/doc/features.html#indent-output" , true );
            
            {
            	serializer.startTag( null , CONFIG_MAIN_TAG );
            	
            	{
            		int iNumPatterns = m_Examplars.size();
            		
            		// 파일 갯수
            		serializer.attribute( null , CONFIG_MAIN_NUM_PATTERN_TAG , String.valueOf( iNumPatterns ) );
            		serializer.attribute( null , CONFIG_MAIN_MAX_EXAMPLARS_TAG , String.valueOf( m_iNumMaxExamplars ) );
            		serializer.attribute( null , CONFIG_MAIN_ANGLE_THRESHOLD_TAG , String.valueOf( m_iAngleThreshold ) );
            		serializer.attribute( null , CONFIG_MAIN_DISTANCE_THRESHOLD_TAG , String.valueOf( m_iDistanceThreshold ) );
            		
            		
            		for ( int i = 0 ; i < iNumPatterns ; i++ )
            		{
            			Examplar e = m_Examplars.get( i );
            			
            			if ( e == null )
            			{
            				continue;
            			}
            			
            			serializer.startTag( null , CONFIG_PATTERN_TAG );

            			{
	            			serializer.attribute( null , CONFIG_PATTERN_ID_TAG , String.valueOf( e.GetID() ) );
	            			serializer.attribute( null , CONFIG_PATTERN_DESCRIPTION_TAG , e.GetDescription() );
	            			serializer.attribute( null , CONFIG_PATTERN_ICON_TAG , e.GetIcon() );
            			}
            			
            			serializer.endTag( null , CONFIG_PATTERN_TAG );
            		}
            		
            	}
            	
            	serializer.endTag( null , CONFIG_MAIN_TAG );
            }
            
            serializer.endDocument();
            //write xml data into the FileOutputStream
            serializer.flush();
            
            //finally we close the file stream
            fos.close();
		}
		catch ( Exception e )
		{
			e.printStackTrace();
			
			return false;
		}
		
		return true;		
	}

	public boolean LoadConfigFile()
	{
		try
		{
			// 파일 패스 체크
			File file = new File( m_strDataPath );
			if ( !file.exists() )
			{
				return false;
			}
			
			file = new File( m_strDataPath + "/" + CONFIG_FILE_NAME_TAG );
			
			if ( !file.exists() )
			{
				return false;				
			}
			
			FileInputStream fis = new FileInputStream ( file );

	        //XmlPullParser를 사용하기 위해서 생성합니다.
	        XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 
	        XmlPullParser parser = factory.newPullParser();
	        
            //we set the FileInputStream as input for the XmlPullParser, using UTF-8 encoding
	        parser.setInput( fis , "UTF-8" );
	        
	        int parserEvent = parser.getEventType();
	        
	        while ( parserEvent != XmlPullParser.END_DOCUMENT )
	        {
	        	switch ( parserEvent )
	        	{
	        		case XmlPullParser.START_TAG:
	        			
	        			String strTagName = parser.getName();
	        			
	        			if ( strTagName.equals( CONFIG_MAIN_TAG ) )
	        			{
	        				int iNumAttributes = parser.getAttributeCount();
	        				
	        				for ( int i = 0 ; i < iNumAttributes ; i++ )
	        				{
	        					String strAttributeName = parser.getAttributeName( i );
	        					
	        					if ( strAttributeName.equals( CONFIG_MAIN_NUM_PATTERN_TAG ) )
	        					{
	        						String strNumPatterns = parser.getAttributeValue( i );
//	        						m_iNumPatterns = Integer.valueOf( strNumPatterns );
	        					}
	        					else if ( strAttributeName.equals( CONFIG_MAIN_MAX_EXAMPLARS_TAG ) )
	        					{
	        						String strNumMaxExamplars = parser.getAttributeValue( i );
	        						m_iNumMaxExamplars = Integer.valueOf( strNumMaxExamplars );
	        					}
	        					else if ( strAttributeName.equals( CONFIG_MAIN_ANGLE_THRESHOLD_TAG ) )
	        					{
	        						String strThreshold = parser.getAttributeValue( i );
	        						m_iAngleThreshold = Integer.valueOf( strThreshold );
	        					}
	        					else if ( strAttributeName.equals( CONFIG_MAIN_DISTANCE_THRESHOLD_TAG ) )
	        					{
	        						String strThreshold = parser.getAttributeValue( i );
	        						m_iDistanceThreshold = Integer.valueOf( strThreshold );
	        					}
	        				}
	        			}
	        			else if ( strTagName.equals( CONFIG_PATTERN_TAG ) )
	        			{
	        				int iPatternID = 0;
	        				int iNumAttributes = parser.getAttributeCount();
	        				
	        				boolean bIsAlreadyLoaded = false;

	        				for ( int i = 0 ; i < iNumAttributes ; i++ )
	        				{
	        					String strAttributeName = parser.getAttributeName( i );
	        					
	        					if ( strAttributeName.equals( CONFIG_PATTERN_ID_TAG ) )
	        					{
	        						String strPatternID = parser.getAttributeValue( i );
	        						iPatternID = Integer.valueOf( strPatternID );
	        						
	        						if ( IsExistExamplar( iPatternID ) )
	        						{
	        							bIsAlreadyLoaded = true;
	        						}
	        						else
	        						{
	        							LoadExamplar( iPatternID );
	        						}
	        					}
	        					else if ( strAttributeName.equals( CONFIG_PATTERN_DESCRIPTION_TAG ) )
	        					{
	        						if ( bIsAlreadyLoaded == false )
	        						{
		        						Examplar currExamplar = GetExamplar( iPatternID );
		        						
		        						if ( currExamplar != null )
		        						{
		        							String strPatternDescription = parser.getAttributeValue( i );
		        							currExamplar.SetDescription( strPatternDescription );
		        						}
	        						}
	        					}
	        					else if ( strAttributeName.equals( CONFIG_PATTERN_ICON_TAG ) )
	        					{
	        						if ( bIsAlreadyLoaded == false )
	        						{
		        						Examplar currExamplar = GetExamplar( iPatternID );
	
		        						if ( currExamplar != null )
		        						{
		        							String strPatternIcon = parser.getAttributeValue( i );
		        							currExamplar.SetIcon( strPatternIcon );
		        						}
	        						}
	        					}
	        				}
	        			}
	        			else
	        			{
	        			}
	        			
	        			break;

	        		case XmlPullParser.END_TAG:

	        			break;
	        			
	        		case XmlPullParser.TEXT:

	        			break;
	        			
	        		default:

	        			break;
	        	}
	        	
	        	parserEvent = parser.next();
	        }
		}
		catch ( Exception e )
		{
			e.printStackTrace();
			
			return false;
		}
		
		return true;
	}

	public Examplar CreateExamplar( int iID )
	{
		Examplar e = new Examplar( this , iID );
		
		if ( e != null )
		{
			InsertExamplar( iID , e );
			
			return e;
		}
		
		return null;
	}
	
	public Examplar GetExamplar( int iID )
	{
		if ( IsExistExamplar( iID ) )
		{
			return m_Examplars.get( iID );
		}
		
		return null;
	}
	
	public boolean IsExistExamplar( int iID )
	{
		return m_Examplars.containsKey( iID );
	}

	public boolean LoadExamplar( int iID )
	{
		Examplar e = new Examplar( this , iID );
		
		if ( e != null )
		{
			if ( e.LoadConfigFile( m_strDataPath ) )
			{
				// 대표값 정보 저장
				InsertExamplar( iID , e );
				// 대표값 로딩
				e.LoadExamplarFile( m_strDataPath );
				
				return true;
			}
		}

		return false;
	}

	private void InsertExamplar( int iID , Examplar e )
	{
		m_Examplars.put( iID , e );
	}
	
	public boolean Compare( AccelValueFileData data , CompareResult result )
	{
		if ( m_Examplars.isEmpty() )
		{
			return false;
		}
		
		result.Clear();
		
		int iNumExamplars = m_Examplars.size();
		
		for ( int i = 0 ; i < iNumExamplars ; i++ )
		{
			Examplar e = m_Examplars.get( i );
			
			if ( e == null )
			{
				continue;
			}
			
			CompareHistory h = new CompareHistory();
			
			CompareResult r = new CompareResult();
			double a = e.Compare( data , h , r );
			
			if ( result.fAccelerate > a )
			{
				result.iID = i;
				result.fAccelerate = r.fAccelerate;

				if ( result.fDistance > r.fDistance )
				{
					result.fDistance = r.fDistance;
				}
			}
			
			result.InsertHistory( i , h );
		}
		
		if ( ( GetAngleThreshold() > result.fAccelerate ) && ( GetDistanceThreshold() > result.fDistance ) )
		{
			return true;
		}

		return false;
	}
}
